<?php

namespace yunj\init\step;

use think\facade\Db;

/**
 * 环境检测
 * Class EnvCheck
 * @package yunj\init\step
 */
class EnvCheck extends Step {

    public function handle() {
        $this->checkBase();
        $this->checkPhpClassModuleFunc();
        $this->checkFileConfig();
        return self::RES_SUCCESS;
    }

    /**
     * 检测基础的
     */
    private function checkBase() {
        // os
        $this->info("操作系统=>" . PHP_OS);

        // php version
        if (version_compare(PHP_VERSION, '7.2.5', '<')) {
            throw new \RuntimeException("PHP版本过低，最少需要PHP7.2.5，请升级PHP版本！");
        } else {
            $this->info("PHP版本=>" . PHP_VERSION);
        }
    }

    /**
     * 检测类、模块、函数
     */
    private function checkPhpClassModuleFunc() {
        $items = [
            // 类
            "class" => [
                "desc" => "类",
                "items" => ["pdo"]
            ],
            // 模块
            "module" => [
                "desc" => "模块",
                "items" => ["pdo_mysql", "zip", "fileinfo", "curl", "redis"]
            ],
            // 函数
            "func" => [
                "desc" => "函数",
                "items" => [
                    "mb_strlen", "gzopen",
                    'gd_info' => ['desc' => 'GD库']
                ]
            ]
        ];
        foreach ($items as $k => $v) {
            foreach ($v['items'] as $kk => $vv) {
                switch ($k) {
                    case "class":
                        $pass = class_exists(is_string($vv) ? $vv : $kk);
                        break;
                    case "module":
                        $pass = extension_loaded(is_string($vv) ? $vv : $kk);
                        break;
                    case "func":
                        $pass = function_exists(is_string($vv) ? $vv : $kk);
                        break;
                }
                if (!isset($pass)) continue;
                $msg = "PHP{$v['desc']}=>" . (is_array($vv) && $vv['desc'] ? $vv['desc'] : $vv);
                if (!$pass) throw new \RuntimeException($msg . " 不支持");
                $this->info($msg . " 支持");
            }
        }

    }

    /**
     * 检测文件配置
     */
    private function checkFileConfig() {
        // listen AppInit
        $appEvent = include ds_replace(root_path() . '/app/event.php');
        $listenAppInit = $appEvent['listen']['AppInit'] ?? [];
        if (!is_array($listenAppInit)) $listenAppInit = [];
        if (!$listenAppInit || !in_array("yunj\core\Init", $listenAppInit)) {
            $msg = <<<EOF
请完善应用初始化事件监听配置
文件路径：项目根目录/app/event.php
内容如下：
return [
    'listen'    => [
        'AppInit'  => [
            "yunj\core\Init",    // 云静Admin初始化处理
            ...
        ],...
    ],...
];
EOF;

            throw new \RuntimeException($msg);
        }
        $this->info("文件配置=>应用初始化事件监听 已完善");

        // cache redis
        try {
            $res = redis()->ping();
        } catch (\Throwable $e) {
            $msg = <<<EOF
请完善redis缓存通道配置，并开启redis服务
文件路径：项目根目录/config/cache.php
内容如下：
return [
    'stores'  => [
        'redis'   =>  [
            'type'   => 'redis',        // 驱动方式
            'host'   => '127.0.0.1',    // 服务器地址
            'prefix' => '******',       // 缓存前缀
            'expire' => 3600,           // 缓存有效期 0表示永久缓存
            ...
        ],...
    ],...
];
EOF;
            $msg = exception_to_str($e) . "\r\n" . $msg;
            throw new \RuntimeException($msg);
        }
        $this->info("文件配置=>redis缓存通道 已完善");

        // database
        try {
            Db::connect()->execute('select version()');
        } catch (\Throwable $e) {
            $msg = <<<EOF
请完善MySql数据库配置，并开启数据库服务
文件路径：项目根目录/config/database.php
内容如下：
return [
  'default' => 'mysql',
  'connections' => [
    'mysql' => [
      'type' => 'mysql',            // 数据库类型
      'hostname' => '127.0.0.1',    // 服务器地址
      'database' => '数据库名',      // 数据库名
      'username' => '数据库用户名',  // 用户名
      'password' => '数据库密码',    // 密码
      'hostport' => '3306',         // 端口
      'charset' => 'utf8mb4',       // 数据库编码，建议和创建数据库时的编码保持一致
      'prefix' => 'yj_',            // 数据库表前缀
      ...
    ],...
  ],...
];
EOF;
            $msg = exception_to_str($e) . "\r\n" . $msg;
            throw new \RuntimeException($msg);
        }
        $this->info("文件配置=>MySql数据库配置 已完善");
    }

}